/*
Module : SQLiteWrappers.h
Purpose: Defines the interface for a set of C++ wrapper classes which encapsulate SQLite v3 (http://www.sqlite.org).
History: PJN / 13-06-2012 1. Initial public release
         PJN / 28-06-2012 1. CValue methods have been made const where appropriate
                          2. CStatement methods have been made const where appropriate
                          3. Implemented a CStatement::ExecRowset method which provides STL iterator accessor to the 
                          returned rowset. The class returned from ExecRowset is SQLite3::CRowset which providess an 
                          input STL iterator to traverse though all the rows returned by SQLite3::CStatement::Step. 
                          Each row as returned from the CRowset iterator is represented by a SQLite3::CRow. Finally 
                          SQLite3::CRow provides a random access STL iterator to all the columns returning a 
                          SQLite3::CValue
                          4. Two additional methods called SQLite3::CDB::ExecRowset and SQLite3::CDB::ExecRowset16 are
                          provided which encapsulate SQLite3::CStatement::ExecRowset which do not require any parameter
                          binding. The output parameter from these two methods is a SQLite3::CRowset2 which contains
                          an SQLite3::CStatement as a member variable.
                          5. Addition of a "SQLITE3WRAPPERS_LOCAL_INCLUSION" pre-processor define which if set will 
                          cause SQLite3 to be pulled in via a #include "SQLite3.h" instead of via #include <SQLite3.h>.
                          This allows SQLiteWrappers to be included in projects which statically compile to SQLite3 
                          from the same directory as your application code.
         PJN / 07-07-2012 1. const and const_reverse iterators have been added to CRow class.
                          2. CRow column iterators now support std::distance
                          3. Fixed a number of /analyze compiler warnings
                          4. Classes now support a SQLITE3WRAPPERS_WCHAR_T_SUPPORT preprocessor define which treats
                          all UTF16 strings as wchar_t* instead of void*. This can help avoid client code needing to
                          do casts where it has a wchar_t data type defined. It also can help find errors where you
                          pass UTF8 or narrow strings to a method which requires a UTF16 string. These checks can be
                          made more useful if you are using the /Zc:wchar_t VC compiler setting.
                          5. CStatement::Bind and Bind16 methods which take UTF8 and UTF16 strings now use a default
                          value for the length parameter
         PJN / 21-07-2012 1. SQLITE3WRAPPERS_WCHAR_T_SUPPORT preprocessor value has been removed and been replaced with 
                          the opposite which is SQLITE3WRAPPERS_NO_WCHAR_T_SUPPORT. By default the classes will now 
                          support wchar_t string values unless the new SQLITE3WRAPPERS_NO_WCHAR_T_SUPPORT is defined.
                          2. Removed unnecessary reinterpret_cast's from the sample app.
         PJN / 23-02-2013 1. Updated copyright details.
                          2. Added support to the CStatement::Bind* methods to support binding by named parameter. 
                          Thanks to "Prepost" for suggesting this nice addition.
         PJN / 25-03-2016 1. Updated copyright details.
                          2. Updated the code to clean compile in VC 2013 & VC 2015
                          3. Addition of a "SQLITE3WRAPPERS_WIN32_INCLUSION" pre-processor define which if set will
                          cause SQLite3 to be pulled in via a #include <winsqlite\winsqlite3.h>. This allows SQLiteWrappers 
                          to be compiled against the Windows 10 DLL version of SQLite. Please note that to use this you must 
                          use the Windows 10.0.10586.0 SDK. Note that even when you do this you will probably get import errors 
                          trying to link your code. This is because the version of SQLite included in Windows 10 is 3.8.8.3 
                          and the winsqlite3.h header file included in the Windows SDK does not have the correct defines in 
                          it to allow you to specify the __stdcall calling convention when linking to the DLL. You can change
                          the calling convention on the translation unit which includes SQLiteWrappers.h in your 
                          application by using the __stdcall (/Gz) compiler setting and then your code should link properly. 
                          A checkin was done in March 2015 to the SQLite codebase which addresses this and you should expect 
                          to see this fix in the next release of the Windows 10 SDK. For the moment because of this issue, 
                          it is still easiest to just add the SQLite amalgamation files to your Visual Studio project to pull 
                          in support for SQLite3.
                          4. Updated the code to compile against SQLite 3.11.1. Added support for sqlite3_close_v2, 
                          sqlite3_malloc64, sqlite3_realloc64, sqlite3_bind_blob64, sqlite3_bind_text64, 
                          sqlite3_bind_zeroblob64, sqlite3_value_subtype, sqlite3_value_dup, sqlite3_value_free,
                          sqlite3_stmt_scanstatus, sqlite3_stmt_scanstatus_reset, sqlite3_db_cacheflush, 
                          sqlite3_snapshot_get & sqlite3_snapshot_open

Copyright (c) 2012 - 2016 by PJ Naughter (Web: www.naughter.com, Email: pjna@naughter.com)

All rights reserved.

Copyright / Usage Details:

You are allowed to include the source code in any product (commercial, shareware, freeware or otherwise) 
when your product is released in binary form. You are allowed to modify the source code in any way you want 
except you cannot modify the copyright details at the top of each module. If you want to distribute source 
code with your application, then you are only allowed to distribute versions released by the author. This is 
to maintain a single distribution point for the source code. 

*/


////////////////////////// Macros / Defines ///////////////////////////////////

#pragma once

#ifndef __SQLITE3WRAPPERS_H__
#define __SQLITE3WRAPPERS_H__

#ifndef CSQLITEWRAPPERS_EXT_CLASS
#define CSQLITEWRAPPERS_EXT_CLASS
#endif //#ifndef CSQLITEWRAPPERS_EXT_CLASS


////////////////////////// Includes ///////////////////////////////////////////

#ifndef _SQLITE3_H_
#ifdef SQLITE3WRAPPERS_WIN32_INCLUSION
#include <winsqlite\winsqlite3.h>
#pragma comment(lib, "winsqlite3.lib") //Automatically link in the Windows SQLite3 dll
#elif SQLITE3WRAPPERS_LOCAL_INCLUSION
#include "sqlite3.h"
#else
#include <SQLite3.h>
#endif //#ifdef SQLITE3WRAPPERS_WIN32_INCLUSION
#endif // #ifndef _SQLITE3_H_

#include <assert.h>

#ifndef _ITERATOR_
#pragma message("To avoid this message, please put iterator in your pre compiled header (normally stdafx.h)")
#include <iterator>
#endif //#ifndef _ITERATOR_

#ifndef _VECTOR_
#pragma message("To avoid this message, please put vector in your pre compiled header (normally stdafx.h)")
#include <vector>
#endif //#ifndef _VECTOR_


////////////////////////// Classes ////////////////////////////////////////////

namespace SQLite3
{
//Forward declarations
class CDB;

class CValue //Encapsulates a sqlite3_value*
{
public:
//Constructors / Destructors
  CValue() : m_p(NULL),
             m_bFreeRequired(false)
  {
  }
  
  CValue(const CValue& value) : m_p(value.m_p),
                                m_bFreeRequired(false)
  {
  }
  
  explicit CValue(sqlite3_value* pValue, bool bFreeRequired = false) : m_p(pValue),
                                                                       m_bFreeRequired(bFreeRequired)
  {
  }

  ~CValue()
  {
  __if_exists(CValue::Free)
  {
    if (m_bFreeRequired)
    {
      Free();
      m_bFreeRequired = false;
    }
  }

    if (m_p != NULL)
      m_p = NULL;
  }

  CValue& operator=(const CValue& value)
  {
    if (this != &value)
    {
      Detach();
      Attach(value.m_p);
    }
    
    return *this;
  }
  
//Methods
  const void* Blob() const
  {
    //Validate our parameters
    assert(m_p != NULL);
    
    return sqlite3_value_blob(m_p);
  }
  
  int Bytes() const
  {
    //Validate our parameters
    assert(m_p != NULL);
    
    return sqlite3_value_bytes(m_p);
  }
  
  int Bytes16() const
  {
    //Validate our parameters
    assert(m_p != NULL);
    
    return sqlite3_value_bytes16(m_p);
  }

  double Double() const
  {
    //Validate our parameters
    assert(m_p != NULL);
    
    return sqlite3_value_double(m_p);
  }
  
  int Int() const
  {
    //Validate our parameters
    assert(m_p != NULL);
    
    return sqlite3_value_int(m_p);
  }
    
  sqlite3_int64 Int64() const
  {
    //Validate our parameters
    assert(m_p != NULL);
    
    return sqlite3_value_int64(m_p);
  }

  const unsigned char* Text() const
  {
    //Validate our parameters
    assert(m_p != NULL);
    
    return sqlite3_value_text(m_p);
  }

#ifndef SQLITE3WRAPPERS_NO_WCHAR_T_SUPPORT
  const wchar_t* Text16() const
#else
  const void* Text16() const
#endif //#ifndef SQLITE3WRAPPERS_NO_WCHAR_T_SUPPORT
  {
    //Validate our parameters
    assert(m_p != NULL);
    
  #ifndef SQLITE3WRAPPERS_NO_WCHAR_T_SUPPORT
    return reinterpret_cast<const wchar_t*>(sqlite3_value_text16(m_p));
  #else    
    return sqlite3_value_text16(m_p);
  #endif //#ifndef SQLITE3WRAPPERS_NO_WCHAR_T_SUPPORT
  }

  const void* Text16LE() const
  {
    //Validate our parameters
    assert(m_p != NULL);
    
    return sqlite3_value_text16le(m_p);
  }

  const void* Text16BE() const
  {
    //Validate our parameters
    assert(m_p != NULL);
    
    return sqlite3_value_text16be(m_p);
  }
  
  int Type() const
  {
    //Validate our parameters
    assert(m_p != NULL);
    
    return sqlite3_value_type(m_p);
  }

__if_exists(sqlite3_value_subtype)
{
  unsigned int Subtype() const
  {
    //Validate our parameters
    assert(m_p != NULL);

    return sqlite3_value_subtype(m_p);
  }
}

  int NumericType() const
  {
    //Validate our parameters
    assert(m_p != NULL);
    
    return sqlite3_value_numeric_type(m_p);
  }

__if_exists(sqlite3_value_dup)
{
  CValue Duplicate() const
  {
    //Validate our parameters
    assert(m_p != NULL);

    return CValue(sqlite3_value_dup(m_p), true);
  }
}

__if_exists(sqlite3_value_free)
{
  void Free()
  {
    //Validate our parameters
    assert(m_p != NULL);

    sqlite3_value_free(m_p);
    m_p = NULL;
    m_bFreeRequired = false;
  }
}

  operator sqlite3_value*() const
  {
    return m_p;
  }

  void Attach(sqlite3_value* pValue)
  {
    //Validate our parameters
    assert(m_p == NULL);
    
    m_p = pValue;
  }

  sqlite3_value* Detach()
  {
    sqlite3_value* pValue = m_p;
    m_p = NULL;
    return pValue;
  }

protected:
//Member variables
  sqlite3_value* m_p;
  bool m_bFreeRequired;
};


//forward declaration
class CRowset;


class CStatement //Encapsulates a sqlite3_stmt*
{
public:
//Constructors / Destructors
  CStatement() : m_p(NULL),
                 m_bAutoFinalize(true)
  {
  }
  
  explicit CStatement(sqlite3_stmt* pStmt, bool bAutoFinalize = true) : m_p(pStmt),
                                                                        m_bAutoFinalize(bAutoFinalize)
  {
  }

  ~CStatement()
  {
    if (m_p != NULL)
    {
      if (m_bAutoFinalize)
        Finalize();
      else
        m_p = NULL;
    }
  }

  CStatement& operator=(const CStatement& statement)
  {
    if (this != &statement)
    {
      if (m_p != NULL)
      {
        if (m_bAutoFinalize)
          Finalize();
        else
          m_p = NULL;
      }
      Attach(statement, false);
    }
    
    return *this;
  }
  
//Methods
  int Prepare(CDB& db, const char* zSql, int nByte = -1, const char** pzTail = NULL);
  int Preparev2(CDB& db, const char* zSql, int nByte = -1, const char** pzTail = NULL);
#ifndef SQLITE3WRAPPERS_NO_WCHAR_T_SUPPORT
  int Prepare16(CDB& db, const wchar_t* zSql, int nByte = -1, const wchar_t** pzTail = NULL);
  int Prepare16v2(CDB& db, const wchar_t* zSql, int nByte = -1, const wchar_t** pzTail = NULL);
#else      
  int Prepare16(CDB& db, const void* zSql, int nByte = -1, const void** pzTail = NULL);
  int Prepare16v2(CDB& db, const void* zSql, int nByte = -1, const void** pzTail = NULL);
#endif //#ifndef SQLITE3WRAPPERS_NO_WCHAR_T_SUPPORT

  int Bind(int nIndex, const void* pData, int n, void(* pFree)(void*) = SQLITE_STATIC)
  {
    //Validate our parameters
    assert(m_p != NULL);
    
    return sqlite3_bind_blob(m_p, nIndex, pData, n, pFree);
  }

__if_exists(sqlite3_bind_blob64)
{
  int Bind64(int nIndex, const void* pData, sqlite3_uint64 n, void(*pFree)(void*) = SQLITE_STATIC)
  {
    //Validate our parameters
    assert(m_p != NULL);

    return sqlite3_bind_blob64(m_p, nIndex, pData, n, pFree);
  }
}

  int Bind(const char* zName, const void* pData, int n, void(* pFree)(void*) = SQLITE_STATIC)
  {
    //Convert the name to an index
    int nIndex = ParameterIndex(zName);
    if (nIndex == 0)
      return SQLITE_RANGE;
    
    return Bind(nIndex, pData, n, pFree);
  }

__if_exists(sqlite3_bind_blob64)
{
  int Bind64(const char* zName, const void* pData, sqlite3_uint64 n, void(*pFree)(void*) = SQLITE_STATIC)
  {
    //Convert the name to an index
    int nIndex = ParameterIndex(zName);
    if (nIndex == 0)
      return SQLITE_RANGE;

    return Bind64(nIndex, pData, n, pFree);
  }
}

  int Bind(int nIndex, double dblValue)
  {
    //Validate our parameters
    assert(m_p != NULL);
    
    return sqlite3_bind_double(m_p, nIndex, dblValue);
  }

  int Bind(const char* zName, double dblValue)
  {
    //Convert the name to an index
    int nIndex = ParameterIndex(zName);
    if (nIndex == 0)
      return SQLITE_RANGE;
    
    return Bind(nIndex, dblValue);
  }

  int Bind(int nIndex, int nValue)
  {
    //Validate our parameters
    assert(m_p != NULL);
    
    return sqlite3_bind_int(m_p, nIndex, nValue);
  }

  int Bind(const char* zName, int nValue)
  {
    //Convert the name to an index
    int nIndex = ParameterIndex(zName);
    if (nIndex == 0)
      return SQLITE_RANGE;
    
    return Bind(nIndex, nValue);
  }

  int Bind(int nIndex, sqlite3_int64 nValue)
  {
    //Validate our parameters
    assert(m_p != NULL);
    
    return sqlite3_bind_int64(m_p, nIndex, nValue);
  }

  int Bind(const char* zName, sqlite3_int64 nValue)
  {
    //Convert the name to an index
    int nIndex = ParameterIndex(zName);
    if (nIndex == 0)
      return SQLITE_RANGE;
    
    return Bind(nIndex, nValue);
  }

  int BindNULL(int nIndex)
  {
    //Validate our parameters
    assert(m_p != NULL);
    
    return sqlite3_bind_null(m_p, nIndex);
  }

  int BindNULL(const char* zName)
  {
    //Convert the name to an index
    int nIndex = ParameterIndex(zName);
    if (nIndex == 0)
      return SQLITE_RANGE;
    
    return BindNULL(nIndex);
  }

  int Bind(int nIndex, const char* pData, int n = -1, void(* pFree)(void*) = SQLITE_STATIC)
  {
    //Validate our parameters
    assert(m_p != NULL);
    
    return sqlite3_bind_text(m_p, nIndex, pData, n, pFree);
  }

__if_exists(sqlite3_bind_text64)
{
  int Bind64(int nIndex, const char* pData, sqlite3_uint64 n, void(*pFree)(void*), unsigned char encoding)
  {
    //Validate our parameters
    assert(m_p != NULL);

    return sqlite3_bind_text64(m_p, nIndex, pData, n, pFree, encoding);
  }
}

  int Bind(const char* zName, const char* pData, int n = -1, void(* pFree)(void*) = SQLITE_STATIC)
  {
    //Convert the name to an index
    int nIndex = ParameterIndex(zName);
    if (nIndex == 0)
      return SQLITE_RANGE;
    
    return Bind(nIndex, pData, n, pFree);
  }

#ifndef SQLITE3WRAPPERS_NO_WCHAR_T_SUPPORT
  int Bind16(int nIndex, const wchar_t* pData, int n = -1, void(* pFree)(void*) = SQLITE_STATIC)
#else
  int Bind16(int nIndex, const void* pData, int n = -1, void(* pFree)(void*) = SQLITE_STATIC)
#endif //#ifndef SQLITE3WRAPPERS_NO_WCHAR_T_SUPPORT
  {
    //Validate our parameters
    assert(m_p != NULL);
    
    return sqlite3_bind_text16(m_p, nIndex, pData, n, pFree);
  }

#ifndef SQLITE3WRAPPERS_NO_WCHAR_T_SUPPORT
  int Bind16(const char* zName, const wchar_t* pData, int n = -1, void(* pFree)(void*) = SQLITE_STATIC)
#else
  int Bind16(const char* zName, const void* pData, int n = -1, void(* pFree)(void*) = SQLITE_STATIC)
#endif //#ifndef SQLITE3WRAPPERS_NO_WCHAR_T_SUPPORT
  {
    //Convert the name to an index
    int nIndex = ParameterIndex(zName);
    if (nIndex == 0)
      return SQLITE_RANGE;
    
    return Bind16(nIndex, pData, n, pFree);
  }

  int Bind(int nIndex, const CValue& value)
  {
    //Validate our parameters
    assert(m_p != NULL);
    
    return sqlite3_bind_value(m_p, nIndex, value);
  }

  int Bind(const char* zName, const CValue& value)
  {
    //Convert the name to an index
    int nIndex = ParameterIndex(zName);
    if (nIndex == 0)
      return SQLITE_RANGE;
    
    return Bind(nIndex, value);
  }

  int BindZeroBlob(int nIndex, int n)
  {
    //Validate our parameters
    assert(m_p != NULL);
    
    return sqlite3_bind_zeroblob(m_p, nIndex, n);
  }  

__if_exists(sqlite3_bind_zeroblob64)
{
  int BindZeroBlob64(int nIndex, sqlite3_uint64 n)
  {
    //Validate our parameters
    assert(m_p != NULL);

    return sqlite3_bind_zeroblob64(m_p, nIndex, n);
  }
}

  int BindZeroBlob(const char* zName, int n)
  {
    //Convert the name to an index
    int nIndex = ParameterIndex(zName);
    if (nIndex == 0)
      return SQLITE_RANGE;
    
    return BindZeroBlob(nIndex, n);
  }

__if_exists(sqlite3_bind_zeroblob64)
{
  int BindZeroBlob64(const char* zName, sqlite3_uint64 n)
  {
    //Convert the name to an index
    int nIndex = ParameterIndex(zName);
    if (nIndex == 0)
      return SQLITE_RANGE;

    return BindZeroBlob64(nIndex, n);
  }
}

  int ExecRowset(CRowset& rowset);

  int Step()
  {
    //Validate our parameters
    assert(m_p != NULL);
  
    return sqlite3_step(m_p);
  }
  
  int ColumnCount() const
  {
    //Validate our parameters
    assert(m_p != NULL);
  
    return sqlite3_column_count(m_p);
  }
  
  int ParameterCount() const
  {
    //Validate our parameters
    assert(m_p != NULL);
  
    return sqlite3_bind_parameter_count(m_p);
  }
  
  int ParameterIndex(const char* zName) const
  {
    //Validate our parameters
    assert(m_p != NULL);
  
    return sqlite3_bind_parameter_index(m_p, zName);
  }
  
  const char* ParameterName(int n) const
  {
    //Validate our parameters
    assert(m_p != NULL);

    return sqlite3_bind_parameter_name(m_p, n);
  }

  int Reset()
  {
    //Validate our parameters
    assert(m_p != NULL);
  
    return sqlite3_reset(m_p);
  }

  int Finalize()
  {
    //Validate our parameters
    assert(m_p != NULL);

    int nReturn = sqlite3_finalize(m_p);
    m_p = NULL;
    return nReturn;
  }
    
  const char* ColumnDatabaseName(int n) const
  {
    //Validate our parameters
    assert(m_p != NULL);

    return sqlite3_column_database_name(m_p, n);
  }  
  
#ifndef SQLITE3WRAPPERS_NO_WCHAR_T_SUPPORT
  const wchar_t* ColumnDatabaseName16(int n) const
#else  
  const void* ColumnDatabaseName16(int n) const
#endif //#ifndef SQLITE3WRAPPERS_NO_WCHAR_T_SUPPORT
  {
    //Validate our parameters
    assert(m_p != NULL);

  #ifndef SQLITE3WRAPPERS_NO_WCHAR_T_SUPPORT
    return static_cast<const wchar_t*>(sqlite3_column_database_name16(m_p, n));
  #else
    return sqlite3_column_database_name16(m_p, n);
  #endif //#ifndef SQLITE3WRAPPERS_NO_WCHAR_T_SUPPORT
  }  
  
  const char* ColumnTableName(int n) const
  {
    //Validate our parameters
    assert(m_p != NULL);

    return sqlite3_column_table_name(m_p, n);
  }  
  
#ifndef SQLITE3WRAPPERS_NO_WCHAR_T_SUPPORT
  const wchar_t* ColumnTableName16(int n) const
#else  
  const void* ColumnTableName16(int n) const
#endif //#ifndef SQLITE3WRAPPERS_NO_WCHAR_T_SUPPORT
  {
    //Validate our parameters
    assert(m_p != NULL);

  #ifndef SQLITE3WRAPPERS_NO_WCHAR_T_SUPPORT
    return static_cast<const wchar_t*>(sqlite3_column_table_name16(m_p, n));
  #else
    return sqlite3_column_table_name16(m_p, n);
  #endif //#ifndef SQLITE3WRAPPERS_NO_WCHAR_T_SUPPORT
  }  
  
  const char* ColumnOriginName(int n) const
  {
    //Validate our parameters
    assert(m_p != NULL);

    return sqlite3_column_origin_name(m_p, n);
  }  
  
#ifndef SQLITE3WRAPPERS_NO_WCHAR_T_SUPPORT
  const wchar_t* ColumnOriginName16(int n) const
#else  
  const void* ColumnOriginName16(int n) const
#endif //#ifndef SQLITE3WRAPPERS_NO_WCHAR_T_SUPPORT
  {
    //Validate our parameters
    assert(m_p != NULL);

  #ifndef SQLITE3WRAPPERS_NO_WCHAR_T_SUPPORT
    return static_cast<const wchar_t*>(sqlite3_column_origin_name16(m_p, n));
  #else
    return sqlite3_column_origin_name16(m_p, n);
  #endif //#ifndef SQLITE3WRAPPERS_NO_WCHAR_T_SUPPORT
  }  

  const char* ColumnDecltype(int n) const
  {
    //Validate our parameters
    assert(m_p != NULL);

    return sqlite3_column_decltype(m_p, n);
  }

#ifndef SQLITE3WRAPPERS_NO_WCHAR_T_SUPPORT
  const wchar_t* ColumnDecltype16(int n) const
#else
  const void* ColumnDecltype16(int n) const
#endif //#ifndef SQLITE3WRAPPERS_NO_WCHAR_T_SUPPORT
  {
    //Validate our parameters
    assert(m_p != NULL);

  #ifndef SQLITE3WRAPPERS_NO_WCHAR_T_SUPPORT
    return static_cast<const wchar_t*>(sqlite3_column_decltype16(m_p, n));
  #else  
    return sqlite3_column_decltype16(m_p, n);
  #endif //#ifndef SQLITE3WRAPPERS_NO_WCHAR_T_SUPPORT
  }

  const char* ColumnName(int n) const
  {
    //Validate our parameters
    assert(m_p != NULL);

    return sqlite3_column_name(m_p, n);
  }

#ifndef SQLITE3WRAPPERS_NO_WCHAR_T_SUPPORT
  const wchar_t* ColumnName16(int n) const
#else
  const void* ColumnName16(int n) const
#endif //#ifndef SQLITE3WRAPPERS_NO_WCHAR_T_SUPPORT
  {
    //Validate our parameters
    assert(m_p != NULL);

  #ifndef SQLITE3WRAPPERS_NO_WCHAR_T_SUPPORT
    return static_cast<const wchar_t*>(sqlite3_column_name16(m_p, n));
  #else
    return sqlite3_column_name16(m_p, n);
  #endif //#ifndef SQLITE3WRAPPERS_NO_WCHAR_T_SUPPORT
  }
  
  const void* ColumnBlob(int iCol) const
  {
    //Validate our parameters
    assert(m_p != NULL);
    
    return sqlite3_column_blob(m_p, iCol);
  }
  
  int ColumnBytes(int iCol) const
  {
    //Validate our parameters
    assert(m_p != NULL);
    
    return sqlite3_column_bytes(m_p, iCol);
  }
  
  int ColumnBytes16(int iCol) const
  {
    //Validate our parameters
    assert(m_p != NULL);
    
    return sqlite3_column_bytes16(m_p, iCol);
  }
  
  double ColumnDouble(int iCol) const
  {
    //Validate our parameters
    assert(m_p != NULL);
    
    return sqlite3_column_double(m_p, iCol);
  }
  
  int ColumnInt(int iCol) const
  {
    //Validate our parameters
    assert(m_p != NULL);
    
    return sqlite3_column_int(m_p, iCol);
  }
    
  sqlite3_int64 ColumnInt64(int iCol) const
  {
    //Validate our parameters
    assert(m_p != NULL);
    
    return sqlite3_column_int64(m_p, iCol);
  }
  
  const unsigned char* ColumnText(int iCol) const
  {
    //Validate our parameters
    assert(m_p != NULL);
    
    return sqlite3_column_text(m_p, iCol);
  }

#ifndef SQLITE3WRAPPERS_NO_WCHAR_T_SUPPORT
  const wchar_t* ColumnText16(int iCol) const
#else
  const void* ColumnText16(int iCol) const
#endif //#ifndef SQLITE3WRAPPERS_NO_WCHAR_T_SUPPORT
  {
    //Validate our parameters
    assert(m_p != NULL);

  #ifndef SQLITE3WRAPPERS_NO_WCHAR_T_SUPPORT
    return static_cast<const wchar_t*>(sqlite3_column_text16(m_p, iCol));
  #else  
    return sqlite3_column_text16(m_p, iCol);
  #endif //#ifndef SQLITE3WRAPPERS_NO_WCHAR_T_SUPPORT
  }
  
  int ColumnType(int iCol) const
  {
    //Validate our parameters
    assert(m_p != NULL);
    
    return sqlite3_column_type(m_p, iCol);
  }

  CValue ColumnValue(int iCol) const
  {
    //Validate our parameters
    assert(m_p != NULL);
    
    return CValue(sqlite3_column_value(m_p, iCol), false);
  }
  
  int DataCount() const
  {
    //Validate our parameters
    assert(m_p != NULL);
    
    return sqlite3_data_count(m_p);
  }
  
  int ClearBindings()
  {
    //Validate our parameters
    assert(m_p != NULL);

    return sqlite3_clear_bindings(m_p);
  }

  CDB DB();
    
  const char* SQL() const
  {
    //Validate our parameters
    assert(m_p != NULL);

    return sqlite3_sql(m_p);
  }
  
  int Busy() const
  {
    //Validate our parameters
    assert(m_p != NULL);

    return sqlite3_stmt_busy(m_p);
  }
  
  int ReadOnly() const
  {
    //Validate our parameters
    assert(m_p != NULL);
  
    return sqlite3_stmt_readonly(m_p);
  }

  int Status(int op, int resetFlg)
  {
    //Validate our parameters
    assert(m_p != NULL);
    
    return sqlite3_stmt_status(m_p, op, resetFlg);
  }
  
__if_exists(sqlite3_stmt_scanstatus)
{
  int ScanStatus(int idx, int iScanStatusOp, void *pOut)
  {
    //Validate our parameters
    assert(m_p != NULL);

    return sqlite3_stmt_scanstatus(m_p, idx, iScanStatusOp, pOut);
  }
}

__if_exists(sqlite3_stmt_scanstatus_reset)
{
  void ScanStatusReset()
  {
    //Validate our parameters
    assert(m_p != NULL);

    sqlite3_stmt_scanstatus_reset(m_p);
  }
}

  operator sqlite3_stmt*() const
  {
    return m_p;
  }

  void Attach(sqlite3_stmt* pStmt, bool bAutoFinalize = true)
  {
    //Validate our parameters
    assert(m_p == NULL);
    
    m_p = pStmt;
    m_bAutoFinalize = bAutoFinalize;
  }

  sqlite3_stmt* Detach()
  {
    sqlite3_stmt* pStmt = m_p;
    m_p = NULL;
    m_bAutoFinalize = false;
    return pStmt;
  }

protected:
//Member variables
  sqlite3_stmt* m_p;
  bool          m_bAutoFinalize;
};


//A STL iterator for CRow
template<class _Ty, class _non_const_Ty, class TRow>
class CColumnIterator : public std::iterator<std::random_access_iterator_tag, _Ty>
{
public: 
//Typedefs
  typedef const CColumnIterator const_self_type;
  typedef CColumnIterator       self_type;
  typedef size_t                size_type;

//Constructors / Destructors  
  CColumnIterator() : m_pRow(NULL), 
                      m_nPosition(-1)
  {
  }
  
  CColumnIterator(const_self_type& other) : m_pRow(other.m_pRow),
                                            m_nPosition(other.m_nPosition)
  {
  }

  CColumnIterator(TRow* pRow, int nPosition) : m_pRow(pRow), 
                                               m_nPosition(nPosition)
  {
  }

//Methods
  reference operator*()
  {
    return operator[](m_nPosition);
  }
    
  self_type& operator=(const_self_type& other)
  {
    m_pRow = other.m_pRow;
    m_nPosition = other.m_nPosition;
    
    return *this;
  }  
  
  pointer operator->()
  { 
    return &(operator*()); 
  }

  reference operator[](size_type nPosition)
  {
    //Validate our parameters
    assert(m_pRow != NULL);
  #ifdef _MSC_VER
    __analysis_assume(m_pRow != NULL);
  #endif //#ifdef _MSC_VER

    return m_pRow->operator[](nPosition);
  }
 
  self_type& operator++()
  {
    ++m_nPosition;
    return *this;
  }

  self_type operator++(int)
  {
    self_type tmp(*this);
    ++(*this);
    return tmp;
  }

  self_type& operator--()
  {
    --m_nPosition;
    return *this;
  }
  
  self_type operator--(int)
  {
    self_type tmp(*this);
    --(*this);
    return tmp;
  }
  
  self_type operator+(difference_type n)
  {
    self_type tmp(*this);
    tmp.m_nPosition += n;
    return tmp;
  }
  
  self_type& operator+=(difference_type n) 
  {
    m_nPosition += n;
    return *this;
  }

  self_type operator-(difference_type n)
  {
    self_type tmp(*this);
    tmp.m_nPosition -= n;
    return tmp;
  }
  
  self_type& operator-=(difference_type n) 
  {
    m_nPosition -= n;
    return *this;
  }

  bool operator==(const_self_type& other) const
  {
    return m_nPosition == other.m_nPosition;
  }
  
  bool operator!=(const_self_type& other) const
  {
    return !operator==(other);
  }
  
  bool operator<(const_self_type& other) const
  {
    return m_nPosition < other.m_nPosition;
  }

  bool operator<=(const_self_type& other) const
  {
    return operator<(other) || operator==(other);
  }
  
  bool operator>(const_self_type& other) const
  {
    return !operator<(other);
  }
  
  bool operator>=(const_self_type& other) const
  {
    return operator>(other) || operator==(other);
  }
  
  difference_type operator-(const_self_type& other)
  {
    return m_nPosition - other.m_nPosition;
  } 

protected:
//Member variables
  TRow*           m_pRow;
  difference_type m_nPosition;
};


class CRow //Represents a row as contained in CRowset
{
public:
//Typedefs
  typedef CColumnIterator<CValue, CValue, CRow>                                     iterator;
  typedef CColumnIterator<const CValue, CValue, const CRow>                         const_iterator;
  typedef std::reverse_iterator<CColumnIterator<CValue, CValue, CRow> >             reverse_iterator;
  typedef std::reverse_iterator<CColumnIterator<const CValue, CValue, const CRow> > const_reverse_iterator;
  typedef CValue                                                                    value_type;
  typedef CValue&                                                                   reference;
  typedef const CValue&                                                             const_reference;
  typedef size_t                                                                    size_type;
  typedef iterator::difference_type                                                 difference_type;

//Constructors / Destructors
  CRow(CStatement* pStatement) : m_pStatement(pStatement),
                                 m_nCachedSize(-1)
  {
    //Validate our parameters
    assert(m_pStatement != NULL);
#ifdef _MSC_VER
  __analysis_assume(m_pStatement != NULL);
#endif //#ifdef _MSC_VER

    //Cache the column count  
    m_nCachedSize = m_pStatement->ColumnCount();
  }
  
//Methods 
  iterator begin()
  { 
    return iterator(this, 0); 
  }

  const_iterator begin() const
  { 
    return const_iterator(this, 0); 
  }

  const_iterator cbegin() const
  { 
    return begin(); 
  }

  iterator end()
  { 
    return iterator(this, static_cast<int>(size())); 
  }

  const_iterator end() const
  { 
    return const_iterator(this, static_cast<int>(size())); 
  }

  const_iterator cend() const
  { 
    return end(); 
  }
  
  reverse_iterator rbegin()
  {
    return reverse_iterator(end()); 
  }
  
  const_reverse_iterator rbegin() const
  {
    return const_reverse_iterator(end());
  }

  const_reverse_iterator crbegin() const
  {
    return rbegin();
  }

  reverse_iterator rend()
  {
    return reverse_iterator(begin());
  }
  
  const_reverse_iterator rend() const
  {
    return const_reverse_iterator(begin());
  }	

  const_reverse_iterator crend() const
  {
    return rend();
  }
  
  reference operator[](size_type nPosition) const
  {
    //Validate our parameters
    assert(m_pStatement != NULL);
#ifdef _MSC_VER
  __analysis_assume(m_pStatement != NULL);
#endif //#ifdef _MSC_VER
    assert(nPosition < size());

    //Update the cached value
    m_Value = m_pStatement->ColumnValue(static_cast<int>(nPosition));

    //Return the cached value 
    return m_Value;
  }

  size_type size() const
  {
    return m_nCachedSize;
  }
  
  bool empty() const
  {
    return size() == 0;
  }
    
//Member variables
  CStatement*        m_pStatement;
  mutable value_type m_Value;
  int                m_nCachedSize;
};


class CRowsetIterator //An STL iterator for CRowset
{
public: 
//Typedefs
  typedef CRowsetIterator         self_type;
  typedef std::input_iterator_tag iterator_category;
  typedef CRow                    value_type;
  typedef CRow*                   pointer;
  typedef const CRow*             const_pointer;
  typedef CRow&                   reference;
  typedef const CRow&             const_reference;
  typedef size_t                  size_type;
  typedef ptrdiff_t               difference_type;
  
//Constructors / Destructors  
  CRowsetIterator(CRowset* pRowset, int nPosition);

//Methods
  reference operator*()
  { 
    return m_Row; 
  }
  
  pointer operator->()
  { 
    return &(operator*()); 
  }
   
  self_type& operator++();
  
  self_type operator++(int)
  {
    self_type tmp(*this);
    ++(*this);
    return tmp;
  }
  
  self_type operator+(difference_type n)
  {
    self_type tmp(*this);
    for (int i=0; i<n; i++)
      ++(tmp);
    return tmp;
  }
  
  self_type& operator+=(difference_type n) 
  {
    for (int i=0; i<n; i++)
      operator++();
    return *this;
  }

  bool operator==(const self_type& other) const
  {
    return m_nPosition == other.m_nPosition;
  }
  
  bool operator!=(const self_type& other) const
  {
    return !operator==(other);
  }
  
  bool operator<(const self_type& other) const
  {
    if (m_nPosition == -1 && other.m_nPosition == -1)
      return false;
    else if (m_nPosition == -1)
      return false;
    else if (other.m_nPosition == -1)
      return true;
    else
      return m_nPosition < other.m_nPosition;
  }

  bool operator<=(const self_type& other) const
  {
    return operator<(other) || operator==(other);
  }
  
  bool operator>(const self_type& other) const
  {
    return !operator<(other);
  }
  
  bool operator>=(const self_type& other) const
  {
    return operator>(other) || operator==(other);
  }

protected:
//Member variables
  CRowset*      m_pRowset;
  value_type    m_Row;
  sqlite3_int64 m_nPosition;
};


class CRowset //Encapsulates a rowset as returned from CStatement::ExecRowset
{
public:
//Typedefs
  typedef CRowsetIterator iterator; 

//Constructors / Destructors
  CRowset() : m_pStatement(NULL),
              m_nFirstStepReturnValue(SQLITE_ERROR)
  {
  }
  
//Methods 
  iterator begin()
  { 
    if (m_nFirstStepReturnValue == SQLITE_ROW)
      return iterator(this, 0);
    else
      return end(); 
  }

  iterator end()
  { 
    return iterator(this, -1); 
  }

protected:
//Member variables
  int m_nFirstStepReturnValue;
  CStatement* m_pStatement;
  
  friend class CRowsetIterator;
  friend class CStatement;
};


class CValue2 : public CValue //version of CValue with an embedded CStatement. Used by the CDB::ExecScalar[16] methods
{
public:
//Constructors / Destructors  
  CValue2() : CValue()
  {
  }
  
  CValue2(const CValue2& value) : CValue(value)
  {
  }
  
//Methods
  CValue2& operator=(CValue2& value)
  {
    if (this != &value)
    {
      __super::operator=(value);
      m_Statement = value.m_Statement;
    }
    
    return *this;
  }

  CValue2& operator=(const CValue& value)
  {
    //Delegate to our base class 
    __super::operator=(value);
    
    return *this;
  }

//Member variables
  CStatement m_Statement;
};  


class CRowset2 : public CRowset //version of CRowset with an embedded CStatement. Used by the CDB::ExecRowset[16] methods
{
public:
//Constructors / Destructors  
  CRowset2() : CRowset()
  {
  }
  
//Member variables
  CStatement m_Statement;
};  


class CDB //Encapsulates a sqlite3* 
{
public:
//Constructors / Destructors
  CDB() : m_p(NULL),
          m_bAutoClose(false)
  {
  }
  
  explicit CDB(sqlite3* pDB, bool bAutoClose = true) : m_p(NULL),
                                                       m_bAutoClose(bAutoClose)
  {
    Attach(pDB, bAutoClose);
  }

  ~CDB()
  {
    if (m_p != NULL)
    {
      if (m_bAutoClose)
        Close();
      else
        m_p = NULL;
    }
  }

  CDB& operator=(const CDB& db)
  {
    if (this != &db)
    {
      if (m_p != NULL)
      {
        if (m_bAutoClose)
          Close();
        else
          m_p = NULL;
      }
      Attach(db, false);
    }
    
    return *this;
  }
  
//Methods
  int Open(const char* filename)
  {
    //Validate our parameters
    assert(m_p == NULL);
    
    return sqlite3_open(filename, &m_p);
  }

#ifndef SQLITE3WRAPPERS_NO_WCHAR_T_SUPPORT
  int Open16(const wchar_t* filename)
#else
  int Open16(const void* filename)
#endif //#ifndef SQLITE3WRAPPERS_NO_WCHAR_T_SUPPORT
  {
    //Validate our parameters
    assert(m_p == NULL);
    
    return sqlite3_open16(filename, &m_p);
  }

  int Open(const char* filename, int flags, const char* pszVFS)
  {
    //Validate our parameters
    assert(m_p == NULL);
    
    return sqlite3_open_v2(filename, &m_p, flags, pszVFS);
  }

  int Close()
  {
    //Validate our parameters
    assert(m_p != NULL);
    
    int nReturn = sqlite3_close(m_p);
    m_p = NULL;
    return nReturn;
  }

__if_exists(sqlite3_close_v2)
{
  int Closev2()
  {
    //Validate our parameters
    assert(m_p != NULL);

    int nReturn = sqlite3_close_v2(m_p);
    m_p = NULL;
    return nReturn;
  }
}

  int Changes()
  {
    //Validate our parameters
    assert(m_p != NULL);
    
    return sqlite3_changes(m_p);
  }

  int TotalChanges()
  {
    //Validate our parameters
    assert(m_p != NULL);
    
    return sqlite3_total_changes(m_p);
  }
  
  int BusyHandler(int(* pBusyHandler)(void*, int), void* pData)
  {
    //Validate our parameters
    assert(m_p != NULL);
    
    return sqlite3_busy_handler(m_p, pBusyHandler, pData);
  }
  
  int BusyTimeout(int ms)
  {
    //Validate our parameters
    assert(m_p != NULL);
    
    return sqlite3_busy_timeout(m_p, ms);
  }

  int CollationNeeded(void* pData, void(* pCallback)(void*, sqlite3*, int eTextRep, const char*))
  {
    //Validate our parameters
    assert(m_p != NULL);

    return sqlite3_collation_needed(m_p, pData, pCallback);
  }

#ifndef SQLITE3WRAPPERS_NO_WCHAR_T_SUPPORT
  int CollationNeeded16(void* pData, void(* pCallback)(void*, sqlite3*, int eTextRep, const wchar_t*))
#else
  int CollationNeeded16(void* pData, void(* pCallback)(void*, sqlite3*, int eTextRep, const void*))
#endif //#ifndef SQLITE3WRAPPERS_NO_WCHAR_T_SUPPORT
  {
    //Validate our parameters
    assert(m_p != NULL);

  #ifndef SQLITE3WRAPPERS_NO_WCHAR_T_SUPPORT
    return sqlite3_collation_needed16(m_p, pData, reinterpret_cast<void(*)(void*, sqlite3*, int, const void*)>(pCallback));
  #else  
    return sqlite3_collation_needed16(m_p, pData, pCallback);
  #endif //#ifndef SQLITE3WRAPPERS_NO_WCHAR_T_SUPPORT
  }

  int CreateCollation(const char* zName, int eTextRep, void* pArg, int(* pCompare)(void*, int, const void*, int, const void*))
  {
    //Validate our parameters
    assert(m_p != NULL);

    return sqlite3_create_collation(m_p, zName, eTextRep, pArg, pCompare);
  }

  int CreateCollation(const char* zName, int eTextRep, void* pArg, int(* pCompare)(void*, int, const void*, int, const void*), void(* pDestroy)(void*))
  {
    //Validate our parameters
    assert(m_p != NULL);

    return sqlite3_create_collation_v2(m_p, zName, eTextRep, pArg, pCompare, pDestroy);
  }

#ifndef SQLITE3WRAPPERS_NO_WCHAR_T_SUPPORT
  int CreateCollation16(const wchar_t* zName, int eTextRep, void* pArg, int(* pCompare)(void*, int, const void*, int, const void*))
#else
  int CreateCollation16(const void* zName, int eTextRep, void* pArg, int(* pCompare)(void*, int, const void*, int, const void*))
#endif //#ifndef SQLITE3WRAPPERS_NO_WCHAR_T_SUPPORT
  {
    //Validate our parameters
    assert(m_p != NULL);

    return sqlite3_create_collation16(m_p, zName, eTextRep, pArg, pCompare);
  }

  int CreateFunction(const char* zFunctionName, int nArg, int eTextRep, void* pApp, void(* pFunc)(sqlite3_context*, int, sqlite3_value**),
                     void(* pStep)(sqlite3_context*, int, sqlite3_value**), void(* pFinal)(sqlite3_context*))
  {
    //Validate our parameters
    assert(m_p != NULL);

    return sqlite3_create_function(m_p, zFunctionName, nArg, eTextRep, pApp, pFunc, pStep, pFinal);
  }

#ifndef SQLITE3WRAPPERS_NO_WCHAR_T_SUPPORT
  int CreateFunction16(const wchar_t* zFunctionName, int nArg, int eTextRep, void* pApp, void(* pFunc)(sqlite3_context*, int, sqlite3_value**),
                       void(* pStep)(sqlite3_context*, int, sqlite3_value**), void(* pFinal)(sqlite3_context*))
#else
  int CreateFunction16(const void* zFunctionName, int nArg, int eTextRep, void* pApp, void(* pFunc)(sqlite3_context*, int, sqlite3_value**),
                       void(* pStep)(sqlite3_context*, int, sqlite3_value**), void(* pFinal)(sqlite3_context*))
#endif //#ifndef SQLITE3WRAPPERS_NO_WCHAR_T_SUPPORT
  {
    //Validate our parameters
    assert(m_p != NULL);

    return sqlite3_create_function16(m_p, zFunctionName, nArg, eTextRep, pApp, pFunc, pStep, pFinal);
  }

  int CreateFunction(const char* zFunctionName, int nArg, int eTextRep, void* pApp, void(* pFunc)(sqlite3_context*, int, sqlite3_value**),
                     void(* pStep)(sqlite3_context*, int, sqlite3_value**), void(* pFinal)(sqlite3_context*), void(* pDestroy)(void*))
  {
    //Validate our parameters
    assert(m_p != NULL);

    return sqlite3_create_function_v2(m_p, zFunctionName, nArg, eTextRep, pApp, pFunc, pStep, pFinal, pDestroy);
  }

  int ExtendedResultCodes(int onoff)
  {
    //Validate our parameters
    assert(m_p != NULL);

    return sqlite3_extended_result_codes(m_p, onoff);
  }

  int FileControl(const char* zDbName, int op, void* pData)
  {
    //Validate our parameters
    assert(m_p != NULL);

    return sqlite3_file_control(m_p, zDbName, op, pData);
  }

  int GetAutocommit()
  {
    //Validate our parameters
    assert(m_p != NULL);

    return sqlite3_get_autocommit(m_p);
  }


  bool NextStatement(CStatement& statement)
  {
    //Validate our parameters
    assert(m_p != NULL);

    sqlite3_stmt* pStatement = sqlite3_next_stmt(m_p, statement);
    
    statement.Detach();
    statement.Attach(pStatement, false);
    
    return (pStatement != NULL);
  }

  void Interrupt()
  {
    //Validate our parameters
    assert(m_p != NULL);
    
    return sqlite3_interrupt(m_p);
  }
  
  sqlite3_int64 LastInsertRowID()
  {
    //Validate our parameters
    assert(m_p != NULL);
    
    return sqlite3_last_insert_rowid(m_p);
  }

  int Limit(int id, int newVal)
  {
    //Validate our parameters
    assert(m_p != NULL);
    
    return sqlite3_limit(m_p, id, newVal);
  }

  int EnableLoadExtension(int onoff)
  {
    //Validate our parameters
    assert(m_p != NULL);
    
    return sqlite3_enable_load_extension(m_p, onoff);
  }
  
  int LoadExtension(const char* zFile, const char* zProc, char** pzErrMsg)
  {
    //Validate our parameters
    assert(m_p != NULL);
    
    return sqlite3_load_extension(m_p, zFile, zProc, pzErrMsg);
  }
  
  void* CommitHook(int(* pCallback)(void*), void* pData)
  {  
    //Validate our parameters
    assert(m_p != NULL);

    return sqlite3_commit_hook(m_p, pCallback, pData);
  }
  
  void* RolbackHook(void(* pCallback)(void*), void* pData)
  {  
    //Validate our parameters
    assert(m_p != NULL);

    return sqlite3_rollback_hook(m_p, pCallback, pData);
  }
  
  int ErrorCode()
  {
    //Validate our parameters
    assert(m_p != NULL);
    
    return sqlite3_errcode(m_p);
  }  

  int ExtendedErrorCode()
  {
    //Validate our parameters
    assert(m_p != NULL);
    
    return sqlite3_extended_errcode(m_p);
  }  
  
  const char* ErrorMessage()
  {
    //Validate our parameters
    assert(m_p != NULL);
    
    return sqlite3_errmsg(m_p);
  }

#ifndef SQLITE3WRAPPERS_NO_WCHAR_T_SUPPORT
  const wchar_t* ErrorMessage16()
#else
  const void* ErrorMessage16()
#endif //#ifndef SQLITE3WRAPPERS_NO_WCHAR_T_SUPPORT
  {
    //Validate our parameters
    assert(m_p != NULL);
  
  #ifndef SQLITE3WRAPPERS_NO_WCHAR_T_SUPPORT
    return static_cast<const wchar_t*>(sqlite3_errmsg16(m_p));
  #else  
    return sqlite3_errmsg16(m_p);
  #endif //#ifndef SQLITE3WRAPPERS_NO_WCHAR_T_SUPPORT
  }

  int Exec(const char* sql, int(* pCallback)(void*, int, char**, char**) = NULL, void* pData = NULL, char** errmsg = NULL)
  {
    //Validate our parameters
    assert(m_p != NULL);
    
    return sqlite3_exec(m_p, sql, pCallback, pData, errmsg);
  }

  int ExecScalar(const char* sql, CValue2& value)
  {
    //Prepare the statement
    if (value.m_Statement.operator sqlite3_stmt*() != NULL)
      value.m_Statement.Finalize();
    int nRet = value.m_Statement.Preparev2(*this, sql);
    if (nRet != SQLITE_OK)
      return nRet;
      
    //Check we have got back at least one column  
    if (value.m_Statement.ColumnCount() < 1)
      return SQLITE_ERROR;
      
    //Move to the first row of the recordset
    nRet = value.m_Statement.Step();
    if (nRet == SQLITE_ROW)
      value = value.m_Statement.ColumnValue(0);
    else
      nRet = SQLITE_ERROR;
  
    return nRet;
  }

#ifndef SQLITE3WRAPPERS_NO_WCHAR_T_SUPPORT
  int Exec16Scalar(const wchar_t* sql, CValue2& value)
#else
  int Exec16Scalar(const void* sql, CValue2& value)
#endif //#ifndef SQLITE3WRAPPERS_NO_WCHAR_T_SUPPORT
  {
    //Prepare the statement
    if (value.m_Statement.operator sqlite3_stmt*() != NULL)
      value.m_Statement.Finalize();
    int nRet = value.m_Statement.Prepare16v2(*this, sql);
    if (nRet != SQLITE_OK)
      return nRet;
      
    //Check we have got back at least one column  
    if (value.m_Statement.ColumnCount() < 1)
      return SQLITE_ERROR;
      
    //Move to the first row of the recordset
    nRet = value.m_Statement.Step();
    if (nRet == SQLITE_ROW)
      value = value.m_Statement.ColumnValue(0);
    else
      nRet = SQLITE_ERROR;
  
    return nRet;
  }

  int ExecRowset(const char* sql, CRowset2& rowset)
  {
    //Prepare the statement
    if (rowset.m_Statement.operator sqlite3_stmt*() != NULL)
      rowset.m_Statement.Finalize();
    int nRet = rowset.m_Statement.Preparev2(*this, sql);
    if (nRet != SQLITE_OK)
      return nRet;
          
    //Move to the first row of the recordset
    return rowset.m_Statement.ExecRowset(rowset);
  }

#ifndef SQLITE3WRAPPERS_NO_WCHAR_T_SUPPORT
  int ExecRowset16(const wchar_t* sql, CRowset2& rowset)
#else
  int ExecRowset16(const void* sql, CRowset2& rowset)
#endif //#ifndef SQLITE3WRAPPERS_NO_WCHAR_T_SUPPORT
  {
    //Prepare the statement
    if (rowset.m_Statement.operator sqlite3_stmt*() != NULL)
      rowset.m_Statement.Finalize();
    int nRet = rowset.m_Statement.Prepare16v2(*this, sql);
    if (nRet != SQLITE_OK)
      return nRet;
          
    //Move to the first row of the recordset
    return rowset.m_Statement.ExecRowset(rowset);
  }

  int OverloadFunction(const char* zFuncName, int nArg)
  {
    //Validate our parameters
    assert(m_p != NULL);
  
    return sqlite3_overload_function(m_p, zFuncName, nArg);
  }

  void* Trace(void(* pTrace)(void*,const char*), void* pData)
  {
    //Validate our parameters
    assert(m_p != NULL);

    return sqlite3_trace(m_p, pTrace, pData);
  }
  
  void* Profile(void(* pProfile)(void*, const char*, sqlite3_uint64), void* pData)
  {
    //Validate our parameters
    assert(m_p != NULL);

    return sqlite3_profile(m_p, pProfile, pData);
  }
  
  void ProgressHandler(int n, int(* pCallback)(void*), void* pData)
  {
    //Validate our parameters
    assert(m_p != NULL);

    sqlite3_progress_handler(m_p, n, pCallback, pData);
  }
  
  int CreateModule(const char* zName, const sqlite3_module* p, void* pClientData)
  {
    //Validate our parameters
    assert(m_p != NULL);

    return sqlite3_create_module(m_p, zName, p, pClientData);
  }

  int CreateModule(const char* zName, const sqlite3_module* p, void* pClientData, void(* pDestroy)(void*))
  {
    //Validate our parameters
    assert(m_p != NULL);

    return sqlite3_create_module_v2(m_p, zName, p, pClientData, pDestroy);
  }

  const char* DBFilename(const char* zDbName)
  {
    //Validate our parameters
    assert(m_p != NULL);

    return sqlite3_db_filename(m_p, zDbName);
  }
  
  sqlite3_mutex* DBMutex()
  {  
    //Validate our parameters
    assert(m_p != NULL);

    return sqlite3_db_mutex(m_p);
  }  

  int DBReleaseMemory()
  {
    //Validate our parameters
    assert(m_p != NULL);

    return sqlite3_db_release_memory(m_p);
  }
  
  int DBStatus(int op, int* pCur, int* pHiwtr, int resetFlg)
  {
    //Validate our parameters
    assert(m_p != NULL);

    return sqlite3_db_status(m_p, op, pCur, pHiwtr, resetFlg);
  }
  
  int DeclareVirtualTable(const char* zSQL)
  {
    //Validate our parameters
    assert(m_p != NULL);

    return sqlite3_declare_vtab(m_p, zSQL);
  }
    
  int DBReadOnly(const char* zDbName)
  {
    //Validate our parameters
    assert(m_p != NULL);

    return sqlite3_db_readonly(m_p, zDbName);
  }

  int TableColumnMetadata(const char* zDbName, const char* zTableName, const char* zColumnName, const char** pzDataType, 
                          const char** pzCollSeq, int* pNotNull, int* pPrimaryKey, int* pAutoinc)
  {
    //Validate our parameters
    assert(m_p != NULL);

    return sqlite3_table_column_metadata(m_p, zDbName, zTableName, zColumnName, pzDataType, pzCollSeq, pNotNull, pPrimaryKey, pAutoinc);
  }
  
  int UnlockNotify(void(* pNotify)(void** apArg, int nArg), void* pNotifyArg)
  {
    //Validate our parameters
    assert(m_p != NULL);

    return sqlite3_unlock_notify(m_p, pNotify, pNotifyArg);
  }

  void* UpdateHook(void(* pHook)(void*, int , char const* ,char const*, sqlite3_int64), void* pHookArg)
  {
    //Validate our parameters
    assert(m_p != NULL);

    return sqlite3_update_hook(m_p, pHook, pHookArg);
  }
  
  int VirtualTableOnConflict()
  {
    //Validate our parameters
    assert(m_p != NULL);

    return sqlite3_vtab_on_conflict(m_p);
  }    
  
  int WALAutoCheckpoint(int N)  
  {
    //Validate our parameters
    assert(m_p != NULL);

    return sqlite3_wal_autocheckpoint(m_p, N);
  }
  
  int WALCheckpoint(const char* zDb)
  {
    //Validate our parameters
    assert(m_p != NULL);

    return sqlite3_wal_checkpoint(m_p, zDb);
  }
  
  int WALCheckpoint(const char* zDb, int eMode, int* pnLog = NULL, int* pnCkpt = NULL)
  {
    //Validate our parameters
    assert(m_p != NULL);

    return sqlite3_wal_checkpoint_v2(m_p, zDb, eMode, pnLog, pnCkpt);
  }
  
  void* WALHook(int(* pHook)(void*, sqlite3*, const char* , int), void* pHookArg)
  {
    //Validate our parameters
    assert(m_p != NULL);

    return sqlite3_wal_hook(m_p, pHook, pHookArg);
  }
  
__if_exists(sqlite3_db_cacheflush)
{
  int CacheFlush()
  {
    //Validate our parameters
    assert(m_p != NULL);

    return sqlite3_db_cacheflush(m_p);
  }
}

__if_exists(sqlite3_snapshot_get)
{
  int SnapshotGet(const char* zSchema, sqlite3_snapshot** ppSnapshot)
  {
    //Validate our parameters
    assert(m_p != NULL);

    return sqlite3_snapshot_get(m_p, zSchema, ppSnapshot);
  }
}

__if_exists(sqlite3_snapshot_open)
{
  int SnapshotOpen(const char* zSchema, sqlite3_snapshot* pSnapshot)
  {
    //Validate our parameters
    assert(m_p != NULL);

    return sqlite3_snapshot_open(m_p, zSchema, pSnapshot);
  }
}

  operator sqlite3*() const
  {
    return m_p;
  }

  void Attach(sqlite3* pDB, bool bAutoClose = true)
  {
    //Validate our parameters
    assert(m_p == NULL);
    
    m_p = pDB;
    m_bAutoClose = bAutoClose;
  }

  sqlite3* Detach()
  {
    sqlite3* pDB = m_p;
    m_p = NULL;
    m_bAutoClose = false;
    return pDB;
  }

protected:
//Member variables
  sqlite3* m_p;
  bool     m_bAutoClose;
};


class CBlob //Encapsulates a sqlite3_blob*
{
public:
//Constructors / Destructors
  CBlob() : m_p(NULL),
            m_bAutoClose(false)
  {
  }
  
  explicit CBlob(sqlite3_blob* pBlob, bool bAutoClose = true) : m_p(pBlob),
                                                                m_bAutoClose(bAutoClose)
  {
  }

  ~CBlob()
  {
    if (m_p != NULL)
    {
      if (m_bAutoClose)
        Close();
      else
        m_p = NULL;
    }
  }

  CBlob& operator=(const CBlob& blob)
  {
    if (this != &blob)
    {
      if (m_p != NULL)
      {
        if (m_bAutoClose)
          Close();
        else
          m_p = NULL;
      }
      Attach(blob, false);
    }
    
    return *this;
  }
  
//Methods
  int Open(CDB& db, const char* zDb, const char* zTable, const char* zColumn, sqlite3_int64 iRow, int flags)
  {
    //Validate our parameters
    assert(m_p == NULL);
  
    return sqlite3_blob_open(db, zDb, zTable, zColumn, iRow, flags, &m_p);
  }

  int Close()
  {
    //Validate our parameters
    assert(m_p != NULL);
    
    return sqlite3_blob_close(m_p);
  }

  int Bytes()
  {
    //Validate our parameters
    assert(m_p != NULL);

    return sqlite3_blob_bytes(m_p);
  }
  
  int Read(void* Z, int N, int iOffset)
  {
    //Validate our parameters
    assert(m_p != NULL);

    return sqlite3_blob_read(m_p, Z, N, iOffset);
  }

  int Reopen(sqlite3_int64 iRow)
  { 
    //Validate our parameters
    assert(m_p != NULL);

    return sqlite3_blob_reopen(m_p, iRow);
  }
  
  int Write(const void* z, int n, int iOffset)
  {
    //Validate our parameters
    assert(m_p != NULL);

    return sqlite3_blob_write(m_p, z, n, iOffset);
  }

  operator sqlite3_blob*() const
  {
    return m_p;
  }

  void Attach(sqlite3_blob* pBlob, bool bAutoClose = true)
  {
    //Validate our parameters
    assert(m_p == NULL);
    
    m_p = pBlob;
    m_bAutoClose = bAutoClose;
  }

  sqlite3_blob* Detach()
  {
    sqlite3_blob* pBlob = m_p;
    m_p = NULL;
    m_bAutoClose = false;
    return pBlob;
  }

protected:
//Member variables
  sqlite3_blob* m_p;
  bool          m_bAutoClose;
};


class CPtr //Encapsulates a pointer which needs to be deallocated using sqlite3_free as well as SQLite printf functionality
{
public:
//Constructors / Destructors
  CPtr() : m_p(NULL),
           m_bAutoFree(false)
  {
  }

  ~CPtr()
  {
    if (m_p != NULL)
    {
      if (m_bAutoFree)
        Free();
      else
        m_p = NULL;
    }
  }

  CPtr& operator=(CPtr& ptr)
  {
    if (this != &ptr)
    {
      if (m_p != NULL)
      {
        if (m_bAutoFree)
          Free();
        else
          m_p = NULL;
      }
      Attach(ptr.Detach(), false);
    }
    
    return *this;
  }
  
//Methods
  bool Allocate(int nBytes)
  {
    //Validate our parameters
    assert(m_p == NULL);
    assert(nBytes != 0); //Does not make sense to allocate zero bytes

    m_p = sqlite3_malloc(nBytes);
    return (m_p != NULL);  
  }

__if_exists(sqlite3_malloc64)
{
  bool Allocate64(sqlite3_uint64 nBytes)
  {
    //Validate our parameters
    assert(m_p == NULL);
    assert(nBytes != 0); //Does not make sense to allocate zero bytes

    m_p = sqlite3_malloc64(nBytes);
    return (m_p != NULL);
  }
}

  bool Reallocate(int nBytes)
  {
    //Validate our parameters
    assert(m_p != NULL);
    assert(nBytes != 0); //Does not make sense to reallocate zero bytes
    
    m_p = sqlite3_realloc(m_p, nBytes);
    return (m_p != NULL);  
  }

__if_exists(sqlite3_realloc64)
{
  bool Reallocate64(sqlite3_uint64 nBytes)
  {
    //Validate our parameters
    assert(m_p != NULL);
    assert(nBytes != 0); //Does not make sense to reallocate zero bytes

    m_p = sqlite3_realloc64(m_p, nBytes);
    return (m_p != NULL);
  }
}

  void Free()
  {
    //Validate our parameters
    assert(m_p != NULL);
    
    sqlite3_free(m_p);
    m_p = NULL;
    m_bAutoFree = false;
  }
  
  bool Format(const char* zFormat, ...)
  {
    if (m_p != NULL)
      Free();  
  
    va_list argp;
    va_start(argp, zFormat);
    m_p = sqlite3_vmprintf(zFormat, argp);
    va_end(argp);
    return (m_p != NULL);
  }

  operator void*() const
  {
    return m_p;
  }

  operator const char*() const
  {
    return static_cast<const char*>(m_p);
  }

  void Attach(void* pPtr, bool bAutoFree = true)
  {
    //Validate our parameters
    assert(m_p == NULL);
    
    m_p = pPtr;
    m_bAutoFree = bAutoFree;
  }

  void* Detach()
  {
    void* pPtr = m_p;
    m_p = NULL;
    return pPtr;
  }

protected:
//Member variables
  void* m_p;
  bool  m_bAutoFree;
};


inline CRowsetIterator::CRowsetIterator(CRowset* pRowset, int nPosition) : m_pRowset(pRowset), 
                                                                           m_Row(pRowset->m_pStatement),
                                                                           m_nPosition(nPosition) 
{
}

inline CRowsetIterator::self_type& CRowsetIterator::operator++()
{
  //Validate our parameters
  assert(m_pRowset != NULL);
#ifdef _MSC_VER
  __analysis_assume(m_pRowset != NULL);
#endif //#ifdef _MSC_VER
  assert(m_pRowset->m_pStatement != NULL);
#ifdef _MSC_VER
  __analysis_assume(m_pRowset->m_pStatement != NULL);
#endif //#ifdef _MSC_VER
  
  int nRet = m_pRowset->m_pStatement->Step();
  assert(nRet == SQLITE_DONE || nRet == SQLITE_ROW);
  ++m_nPosition;

  if (nRet == SQLITE_DONE)
    m_nPosition = -1;
  
  return *this;
}


inline CDB CStatement::DB()
{
  //Validate our parameters
  assert(m_p != NULL);

  CDB db(sqlite3_db_handle(m_p), false);
  return db;
}

inline int CStatement::Prepare(CDB& db, const char* zSql, int nByte, const char** pzTail)
{
  //Validate our parameters
  assert(m_p == NULL);
  assert(db.operator sqlite3*() != NULL);
  
  return sqlite3_prepare(db, zSql, nByte, &m_p, pzTail);
}

inline int CStatement::Preparev2(CDB& db, const char* zSql, int nByte, const char** pzTail)
{
  //Validate our parameters
  assert(m_p == NULL);
  assert(db.operator sqlite3*() != NULL);
  
  return sqlite3_prepare_v2(db, zSql, nByte, &m_p, pzTail);
}

#ifndef SQLITE3WRAPPERS_NO_WCHAR_T_SUPPORT
inline int CStatement::Prepare16(CDB& db, const wchar_t* zSql, int nByte, const wchar_t** pzTail)
#else
inline int CStatement::Prepare16(CDB& db, const void* zSql, int nByte, const void** pzTail)
#endif //#ifndef SQLITE3WRAPPERS_NO_WCHAR_T_SUPPORT
{
  //Validate our parameters
  assert(m_p == NULL);
  assert(db.operator sqlite3*() != NULL);

#ifndef SQLITE3WRAPPERS_NO_WCHAR_T_SUPPORT
  return sqlite3_prepare16(db, zSql, nByte, &m_p, reinterpret_cast<const void**>(pzTail));
#else  
  return sqlite3_prepare16(db, zSql, nByte, &m_p, pzTail);
#endif //#ifndef SQLITE3WRAPPERS_NO_WCHAR_T_SUPPORT
}

#ifndef SQLITE3WRAPPERS_NO_WCHAR_T_SUPPORT
inline int CStatement::Prepare16v2(CDB& db, const wchar_t* zSql, int nByte, const wchar_t** pzTail)
#else
inline int CStatement::Prepare16v2(CDB& db, const void* zSql, int nByte, const void** pzTail)
#endif //#ifndef SQLITE3WRAPPERS_NO_WCHAR_T_SUPPORT
{
  //Validate our parameters
  assert(m_p == NULL);
  assert(db.operator sqlite3*() != NULL);

#ifndef SQLITE3WRAPPERS_NO_WCHAR_T_SUPPORT
  return sqlite3_prepare16_v2(db, zSql, nByte, &m_p, reinterpret_cast<const void**>(pzTail));
#else  
  return sqlite3_prepare16_v2(db, zSql, nByte, &m_p, pzTail);
#endif //#ifndef SQLITE3WRAPPERS_NO_WCHAR_T_SUPPORT
}

inline int CStatement::ExecRowset(CRowset& rowset)
{
  //Execute the first step
  rowset.m_nFirstStepReturnValue = Step();

  //Update the other values in the rowset instance being returned
  rowset.m_pStatement = this;
  
  return rowset.m_nFirstStepReturnValue;
}


}; //namespace SQLite3

#endif //#ifndef __SQLITE3WRAPPERS_H__
